/**
 * Copyright 2021 xpstem.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.xpstem.lelink.command;

import com.xpstem.lelink.enums.CommandCode;
import com.xpstem.lelink.enums.CommandType;
import com.xpstem.lelink.type.*;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * EV3 system commands
 * @author billy zhang
 */
public class EV3SystemCmdFactory {

    private EV3SystemCmdFactory() { }

    /**
     * Write to mailbox
     */
    public static class WriteMailboxCommand<T> extends EV3SystemCommand {
        private String mailboxName;
        private T message;
        private CommandType type;

        public WriteMailboxCommand(String mailboxName, T message) {
            this.mailboxName = mailboxName;
            this.message = message;
        }

        public WriteMailboxCommand(String mailboxName, T message, CommandType type) {
            this.mailboxName = mailboxName;
            this.message = message;
            this.type = type;
        }

        @Override
        public CommandType getType() {
            return type;
        }

        @Override
        public byte[] getPayload() throws IOException {

            Data8 nameLen = Data8.from((short)mailboxName.length()+1);

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            nameLen.writeTo(outputStream);
            outputStream.write(mailboxName.getBytes());
            outputStream.write(0);

            if (message instanceof String) {
                String msg = (String)message;
                Data16 payloadLen = Data16.from(msg.length()+1);
                payloadLen.writeTo(outputStream);
                outputStream.write(msg.getBytes());
                outputStream.write(0);

            } else if (message instanceof Boolean) {
                boolean msg = (Boolean)message;
                Data8.from(1).writeTo(outputStream);
                Data8.from(msg ? 1 : 0).writeTo(outputStream);

            } else if (message instanceof Integer) {

                Integer msg = (Integer) message;
                Data8.from(4).writeTo(outputStream);
                DataF.from(msg).writeTo(outputStream);
            }

            return outputStream.toByteArray();
        }

        @Override
        public CommandCode getCommandCode() {
            return CommandCode.WRITE_MAILBOX;
        }

    }

    /**
     * Transfer trusted pin code to brick
     */
    public static class SetBluetoothPinCommand extends EV3SystemCommand {
        private String macAddress;
        private String pinCode;

        public SetBluetoothPinCommand(String macAddress, String pinCode) {
            this.macAddress = macAddress;
            this.pinCode = pinCode;
        }

        @Override
        protected byte[] getPayload() throws IOException {
            // MAC address length must be 0x06
            Data8 macLen = Data8.from(macAddress.length());
            // pincode length must be 0x04
            Data8 pinLen = Data8.from(pinCode.length());

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            macLen.writeTo(outputStream);
            outputStream.write(macAddress.getBytes());
            pinLen.writeTo(outputStream);
            outputStream.write(pinCode.getBytes());

            return outputStream.toByteArray();
        }

        @Override
        public CommandCode getCommandCode() {
            return CommandCode.SET_BLUETOOTHPIN;
        }

    }

}
